<template>
  <a-card :bordered="false">
    <!-- 查询区域 -->
    <div class="table-page-search-wrapper">
      <a-form layout="inline" @keyup.enter.native="searchQuery">
        <a-row :gutter="24">
          <a-col :xl="6" :lg="7" :md="8" :sm="24">
            <a-form-item label="测试名称">
              <a-input placeholder="请输入测试名称" v-model="queryParam.testName"></a-input>
            </a-form-item>
          </a-col>
          <a-col :xl="6" :lg="7" :md="8" :sm="24">
            <a-form-item label="目标设备名称">
              <a-input placeholder="请输入目标设备名称" v-model="queryParam.equipName"></a-input>
            </a-form-item>
          </a-col>
          <template v-if="toggleSearchStatus">
            <a-col :xl="6" :lg="7" :md="8" :sm="24">
              <a-form-item label="目标设备编号">
                <a-input placeholder="请输入目标设备编号" v-model="queryParam.equipCode"></a-input>
              </a-form-item>
            </a-col>
          </template>
          <a-col :xl="6" :lg="7" :md="8" :sm="24">
            <span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
              <a-button type="primary" @click="searchQuery" icon="search">查询</a-button>
              <a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button>
              <a @click="handleToggleSearch" style="margin-left: 8px">
                {{ toggleSearchStatus ? '收起' : '展开' }}
                <a-icon :type="toggleSearchStatus ? 'up' : 'down'" />
              </a>
            </span>
          </a-col>
        </a-row>
      </a-form>
    </div>
    <!-- 查询区域-END -->

    <!-- 操作按钮区域 -->
    <div class="table-operator">
      <a-button @click="handleAdd" type="primary" icon="plus">新增</a-button>
      <a-button type="primary" icon="download" @click="handleExportXls('测试工程管理')">导出</a-button>
      <a-upload
        name="file"
        :showUploadList="false"
        :multiple="false"
        :headers="tokenHeader"
        :action="importExcelUrl"
        @change="handleImportExcel"
      >
        <a-button type="primary" icon="import">导入</a-button>
      </a-upload>
      <!-- 高级查询区域 -->
      <j-super-query
        :fieldList="superFieldList"
        ref="superQueryModal"
        @handleSuperQuery="handleSuperQuery"
      ></j-super-query>
      <a-dropdown v-if="selectedRowKeys.length > 0">
        <a-menu slot="overlay">
          <a-menu-item key="1" @click="batchDel"><a-icon type="delete" />删除</a-menu-item>
        </a-menu>
        <a-button style="margin-left: 8px"> 批量操作 <a-icon type="down"/></a-button>
      </a-dropdown>
    </div>

    <!-- table区域-begin -->
    <div>
      <div class="ant-alert ant-alert-info" style="margin-bottom: 16px;">
        <i class="anticon anticon-info-circle ant-alert-icon"></i> 已选择
        <a style="font-weight: 600">{{ selectedRowKeys.length }}</a
        >项
        <a style="margin-left: 24px" @click="onClearSelected">清空</a>
      </div>

      <a-table
        ref="table"
        size="middle"
        :scroll="{ x: true }"
        bordered
        rowKey="id"
        :columns="columns"
        :dataSource="dataSource"
        :pagination="ipagination"
        :loading="loading"
        :rowSelection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
        class="j-table-force-nowrap"
        @change="handleTableChange"
      >
        <template slot="htmlSlot" slot-scope="text">
          <div v-html="text"></div>
        </template>
        <template slot="imgSlot" slot-scope="text, record">
          <span v-if="!text" style="font-size: 12px;font-style: italic;">无图片</span>
          <img
            v-else
            :src="getImgView(text)"
            :preview="record.id"
            height="25px"
            alt=""
            style="max-width:80px;font-size: 12px;font-style: italic;"
          />
        </template>
        <template slot="fileSlot" slot-scope="text">
          <span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span>
          <a-button v-else :ghost="true" type="primary" icon="download" size="small" @click="downloadFile(text)">
            下载
          </a-button>
        </template>
        <!-- <span slot="userCaseIds" slot-scope="text, record"> <a @click="handleConfig(record)">编辑配置</a></span> -->
        <span slot="action" slot-scope="text, record">
          <!-- <a-button type="primary" @click="handleGenerateScript(record)">生成</a-button>

          <a-divider type="vertical" /> -->
          <a-button type="primary" @click="handleRunScript(record)" :disabled="isExecuting" :loading="isExecuting">
            {{ isExecuting ? '执行中...' : '执行' }}
          </a-button>

          <a-divider type="vertical" />
          <a-button type="primary" :disabled="isExecuting" @click="handleEdit(record, 2)">编辑</a-button>

          <a-divider type="vertical" />
          <a-button type="primary" @click="handleConfig(record)">用例配置</a-button>

          <a-divider type="vertical" />
          <!-- <a @click="handleConfig(record)">配置</a>

          <a-divider type="vertical" /> -->
          <a-dropdown>
            <a class="ant-dropdown-link">更多 <a-icon type="down"/></a>
            <a-menu slot="overlay">
              <a-menu-item>
                <a @click="handleDetail(record)">详情</a>
              </a-menu-item>
              <a-menu-item>
                <a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)">
                  <a>删除</a>
                </a-popconfirm>
              </a-menu-item>
            </a-menu>
          </a-dropdown>
        </span>
      </a-table>
    </div>

    <a-modal
      title="用例配置"
      width="80%"
      :visible="visible"
      :confirm-loading="confirmLoading"
      @ok="handleOk"
      @cancel="handleCancel"
    >
      <!-- 简化操作提示 -->
      <div class="operation-tips">
        <div>操作提示：点击"复制"按钮自动在当前行下方插入副本，拖动左侧图标可调整行顺序</div>
      </div>
      <a-button type="primary" @click="handleAddTest">
        新增
      </a-button>

      <div class="config-table">
        <table class="ant-table ConfigList" style="width: 100%;">
          <thead>
            <tr>
              <th width="60" align="center">序号</th>
              <th width="80" align="left">拖拽</th>
              <th width="200" align="left">用例名称</th>
              <!-- <th width="300" align="center">用例描述</th> -->
              <!-- 新增用例描述列 -->
              <th align="center">用例</th>
              <th width="180" align="center">操作</th>
            </tr>
          </thead>
          <draggable
            v-model="tableData"
            tag="tbody"
            :options="{
              animation: 150,
              handle: '.drag-handle'
            }"
            @end="saveOrder"
          >
            <tr
              v-for="(record, index) in tableData"
              :key="record.id"
              class="drag-row"
              :class="{ 'selected-row': selectedIndex === index }"
              @click="selectRow(record, index)"
              tabindex="0"
            >
              <td width="60" align="center">
                {{ index + 1 }}
              </td>
              <td width="80" align="center">
                <a-icon type="menu" class="drag-handle" style="cursor: move;" />
              </td>
              <td align="center">{{ record.caseName }}</td>
              <!-- <td width="300" align="left" class="description-cell">
                {{ record.ymlFilePath }}
              </td> -->
              <td align="center">{{ record.ymlFilePath }}</td>
              <td width="220" align="center">
                <a-button size="small" type="primary" @click="openConfig(record.ymlFilePath, record, index)"
                  >配置</a-button
                >
                <a-divider type="vertical" />
                <a-button size="small" type="primary" @click.stop="copyRowToNext(record, index)" title="复制到下方">
                  复制
                </a-button>
                <a-divider type="vertical" />
                <a-popconfirm
                  title="确定要删除这一行吗？"
                  @confirm="deleteRow(index, record.id)"
                  okText="确定"
                  cancelText="取消"
                >
                  <a-button size="small" type="danger" @click.stop title="删除此行">删除</a-button>
                </a-popconfirm>
              </td>
            </tr>
          </draggable>
        </table>
      </div>
    </a-modal>

    <a-modal
      title="配置yml"
      width="50%"
      :visible="visible1"
      :confirm-loading="confirmLoading1"
      @ok="handleOk1"
      @cancel="handleCancel1"
    >
      <config-form
        style="width:100%"
        :yaml-file-url="yamlFileUrl"
        ref="configBox"
        :key="configFormKey"
        form-title="通信配置"
        @submit-success="handleSubmitSuccess"
      />
    </a-modal>
    <a-modal
      title="新增用例"
      width="50%"
      :visible="visible2"
      :confirm-loading="confirmLoading2"
      @ok="handleOk2"
      @cancel="handleCancel2"
    >
      <a-form-model ref="form" :model="model" :rules="validatorRules">
        <a-row>
          <!-- <a-col :span="24">
            <a-form-model-item label="测试名称" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="testName">
              <a-input v-model="model.testName" placeholder="请输入测试名称"></a-input>
            </a-form-model-item>
          </a-col> -->
          <a-col :span="24">
            <a-form-model-item label="关联用例" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="userCaseIds">
              <a-tree
                v-model="model.userCaseIds"
                checkable
                :checkStrictly="true"
                :expanded-keys="expandedKeys"
                :auto-expand-parent="autoExpandParent"
                :selected-keys="selectedKeys"
                :replaceFields="replaceFields"
                :tree-data="options1"
                @expand="handleExpand"
              />
            </a-form-model-item>
          </a-col>
        </a-row>
      </a-form-model>
    </a-modal>
    <engineering-management-modal ref="modalForm" @ok="modalFormOk"></engineering-management-modal>
  </a-card>
</template>

<script>
import draggable from 'vuedraggable'
import '@/assets/less/TableExpand.less'
import { mixinDevice } from '@/utils/mixin'
import { JeecgListMixin } from '@/mixins/JeecgListMixin'
import EngineeringManagementModal from './modules/EngineeringManagementModal'
import { getTestCaseDescription, formatDescription } from '@/utils/yamlLoader'
import { httpAction, getAction, deleteAction } from '@/api/manage'
import ConfigForm from './components/ConfigForm.vue'
export default {
  name: 'EngineeringManagementList',
  mixins: [JeecgListMixin, mixinDevice],
  components: {
    EngineeringManagementModal,
    ConfigForm,
    draggable
  },
  data() {
    return {
      expandedKeys: ['0-0-0', '0-0-1'],
      autoExpandParent: false,
      isExecuting: false, // 执行状态
      checkedKeys: ['0-0-0'],
      selectedKeys: [],
      model: {
        userCaseIds: [] // 确保有初始值
      },
      dataTree: [],
      labelCol: {
        xs: { span: 24 },
        sm: { span: 5 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 16 }
      },
      copiedRow: null, // 被复制的行
      selectedIndex: -1, // 当前选中行索引
      selectedRow: null, // 当前选中行数据
      validatorRules: {},
      columns1: [
        {
          title: '序号',
          dataIndex: '',
          key: 'rowIndex',
          width: 60,
          align: 'center',
          customRender: function(t, r, index) {
            return parseInt(index) + 1
          }
        },
        { title: '拖拽', dataIndex: '', width: 80 },
        { title: '用例名称', dataIndex: 'caseName', width: 200 },
        // { title: '用例描述', dataIndex: 'formattedDescription', width: 300 }, // 新增描述列
        { title: '用例', dataIndex: 'ymlFilePath' },
        { title: '操作', key: 'action', width: 180, align: 'center', scopedSlots: { customRender: 'action' } }
      ],
      tableData: [],
      description: '测试工程管理管理页面',
      // 表头
      columns: [
        {
          title: '#',
          dataIndex: '',
          key: 'rowIndex',
          width: 60,
          align: 'center',
          customRender: function(t, r, index) {
            return parseInt(index) + 1
          }
        },
        {
          title: '工程名称',
          align: 'center',
          dataIndex: 'testName'
        },
        {
          title: '创建人员',
          align: 'center',
          dataIndex: 'tester'
        },
        {
          title: '工程描述',
          align: 'center',
          dataIndex: 'testDescription'
        },

        // {
        //   title: '关联用例',
        //   align: 'center',
        //   dataIndex: 'userCaseIds',
        //   scopedSlots: { customRender: 'userCaseIds' }
        // },
        {
          title: '产品建号',
          align: 'center',
          dataIndex: 'equipName'
        },
        {
          title: '创建时间',
          align: 'center',
          dataIndex: 'createTime'
        },
        // {
        //   title: '目标设备编号',
        //   align: 'center',
        //   dataIndex: 'equipCode'
        // },
        {
          title: '操作',
          dataIndex: 'action',
          align: 'center',
          fixed: 'right',
          width: 147,
          scopedSlots: { customRender: 'action' }
        }
      ],
      url: {
        list: '/engineeringManagement/list',
        testUserCaseList: '/testUserCase/list',
        delete: '/engineeringManagement/delete',
        deleteBatch: '/engineeringManagement/deleteBatch',
        exportXlsUrl: '/engineeringManagement/exportXls',
        importExcelUrl: 'org/engineeringManagement/importExcel',
        treelist: '/testUserCase/queryAllCase',
        getTestById: '/testCaseEngineeringManagement/list',
        deleteTest: '/testCaseEngineeringManagement/delete',
        addBatch: '/testCaseEngineeringManagement/addBatch',
        copyFile: '/sys/common/copyFile'
      },
      dictOptions: {},
      superFieldList: [],
      visible: false,
      confirmLoading: false,
      visible1: false,
      confirmLoading1: false,
      visible2: false,
      confirmLoading2: false,
      yamlFileUrl: '',
      currentConfigRecord: null, // 当前正在配置的记录
      configFormKey: 0, // 用于强制重新渲染ConfigForm
      userCaseIdList: [],
      gData: [],
      currentUserCaseId: [],
      replaceFields: {
        title: 'label',
        key: 'value',
        children: 'children'
      },
      updateSequenceTimer: null,
      originalTableData: [] // 备份原始数据用于比较
    }
  },
  created() {
    this.getSuperFieldList()
  },
  computed: {
    importExcelUrl: function() {
      return `${window._CONFIG['domianURL']}/${this.url.importExcelUrl}`
    },

    options1() {
      if (!this.dataTree || this.dataTree.length === 0) {
        return []
      }

      const validRoots = this.dataTree.filter(node => node.purpose !== 0)

      const treeData = validRoots.map(node => ({
        value: node.id,
        label: node.caseName,
        yml: node.fileYml,
        children: (node.children || [])
          .filter(c => c.purpose !== 0)
          .map(c => ({
            value: c.id,
            label: c.caseName,
            yml: c.fileYml
          }))
      }))

      // 自动设置展开键值为所有第一级节点的key
      this.$nextTick(() => {
        if (treeData.length > 0) {
          this.expandedKeys = treeData.map(item => item.value)
        }
      })

      return treeData
    }
    // gData() {
    //   // 1. 去掉 purpose === 0 的节点
    //   const a = this.currentUserCaseId // 允许通过的 id 白名单
    //   const allow = new Set(a) // 用 Set 做 O(1) 查找

    //   // 1. 先过滤根节点 //没有选中的用例时，直接展示所有的用例
    //   const validRoots = this.currentUserCaseId.length
    //     ? this.tableData.filter(node => allow.has(node.id))
    //     : this.tableData

    //   // 2. 只取两层，不再继续嵌套
    //   return validRoots
    // }
  },
  methods: {
    handleExpand(expandedKeys) {
      console.log('展开的节点:', expandedKeys)
      this.expandedKeys = expandedKeys
    },
    getList() {
      getAction(this.url.treelist).then(res => {
        if (res.success) {
          console.log(res, 'resshu')
          this.dataTree = res.result[0].children
        } else {
          console.error('getDictItems error: : ', res)
          this.dict = []
        }
      })
    },
    handleGenerateScript(record) {
      getAction('/mq/generateScript', { engineeringId: record.id }).then(res => {
        if (res.success) {
          this.$message.success(res.message)
          // 触发提交成功事件
        } else {
          this.$message.warning(res.message)
        }
      })
    },
    handleRunScript(record) {
      if (this.isExecuting) {
        this.$message.warning('正在执行中，请稍候...')
        return
      }

      // 设置执行状态
      this.isExecuting = true

      // 显示执行提示
      // this.$message.loading('脚本执行中，请稍候...', 0)

      // console.log('开始执行脚本:', record)
      // 带参数跳转

      // getAction('/mq/runScript', { engineeringId: record.id }).then(res => {
      getAction('/mq/generateScript', { engineeringId: record.id }).then(res => {
        if (res.success) {
          this.$message.success(res.message)
          this.$router.push({
            path: '/EngineeringManagement/EngineeringManagementList1',
            query: {
              id: record.id
            }
          })
          // 触发提交成功事件
        } else {
          // // 模拟执行过程，5秒后恢复
          this.executeTimer = setTimeout(() => {
            // 清除执行状态
            this.isExecuting = false
            // 清除加载提示
            // this.$message.destroy()
            // this.$message.success('脚本执行完成')

            console.log('脚本执行完成:', record)
          }, 5000)
          this.$message.warning(res.message)
        }
      })
    },
    handleOk2() {
      this.visible2 = false
      let data = []

      // 修复：使用当前表格长度作为起始序号
      const startSeq = this.tableData.length + 1

      this.model.userCaseIds.checked.forEach((i, index) => {
        let obj = {
          engineeringId: this.record.id,
          userCaseId: i,
          seq: startSeq + index // 确保新增的用例序号连续
        }
        data.push(obj)
      })

      console.log(data, '新增的用例数据')
      httpAction(this.url.addBatch, data, 'post').then(res => {
        if (res.success) {
          console.log(res, '新增用例成功')
          // 重新加载数据，确保按seq排序
          getAction(this.url.getTestById, { engineeringId: this.record.id, pageSize: -1 }).then(res => {
            if (res.success) {
              // 按 seq 字段升序排序
              this.tableData = (res.result.records || [])
                .map((item, index) => {
                  return {
                    ...item,
                    seq: item.seq || index + 1
                  }
                })
                .sort((a, b) => (a.seq || 0) - (b.seq || 0))

              // 重新备份数据
              this.backupTableData()
            } else {
              console.error('获取测试用例数据失败:', res)
            }
          })
        } else {
          console.error('新增用例失败:', res)
          this.$message.error('新增用例失败')
        }
      })
    },
    handleCancel2() {
      this.visible2 = false
    },
    handleAddTest() {
      // this.handleEdit(this.record, 1)
      this.getList()
      this.visible2 = true
    },

    handleEdit: function(record, type) {
      this.$refs.modalForm.edit(record, type)
      this.$refs.modalForm.title = '编辑'
      this.$refs.modalForm.disableSubmit = false
    },
    /* 加载用例描述信息 */
    // async loadCaseDescriptions() {
    //   if (!this.tableData || this.tableData.length === 0) return

    //   // 为每个用例加载描述信息
    //   const promises = this.tableData.map(async (record, index) => {
    //     if (!record.fileYml) {
    //       record.formattedDescription = '无配置文件'
    //       return
    //     }

    //     try {
    //       // 设置加载状态
    //       this.$set(record, 'descriptionLoading', true)
    //       console.log(record, '2')
    //       this.$set(record, 'descriptionError', null)
    //       console.log(2, '3')

    //       // 获取描述信息
    //       const description = await getTestCaseDescription(record.fileYml)
    //       console.log(description, 'descriptiondescription')
    //       this.$set(record, 'fullDescription', description)
    //       this.$set(record, 'formattedDescription', formatDescription(description))
    //     } catch (error) {
    //       console.error(`加载用例描述失败1 ${record.caseName}:`, error)
    //       this.$set(record, 'descriptionError', error.message)
    //       this.$set(record, 'formattedDescription', '描述加载失败')
    //     } finally {
    //       this.$set(record, 'descriptionLoading', false)
    //     }
    //   })

    //   await Promise.all(promises)
    // },

    /* 处理配置弹窗显示 */
    handleConfig(record) {
      this.visible = true
      this.record = record
      getAction(this.url.getTestById, { engineeringId: record.id, pageSize: -1 }).then(res => {
        if (res.success) {
          console.log(res, '获取测试用例数据')
          // 修复：按 seq 字段升序排序
          this.tableData = (res.result.records || [])
            .map((item, index) => {
              return {
                ...item,
                seq: item.seq || index + 1
              }
            })
            .sort((a, b) => (a.seq || 0) - (b.seq || 0)) // 按 seq 升序排序

          // 修复：确保在数据加载完成后备份
          this.$nextTick(() => {
            this.backupTableData()
          })
        } else {
          console.error('获取测试用例数据失败:', res)
        }
      })
    },

    /* 复制行到下方 */
    copyRowToNext(record, currentIndex) {
      // 深度复制对象，避免引用问题
      const copiedData = JSON.parse(JSON.stringify(record))

      // 生成新的行数据 - 修复：使用正确的序号计算
      const newRow = {
        ...copiedData,
        id: Date.now() + Math.floor(Math.random() * 1000), // 生成唯一ID
        caseName: this.generateCopyName(copiedData.caseName),
        seq: currentIndex + 2, // 插入位置的序号（当前行是 currentIndex + 1，所以下一行是 currentIndex + 2）
        editable: false,
        // 清除关联ID，避免重复
        userCaseId: undefined
      }

      // 在当前行下方插入新行
      const insertIndex = currentIndex + 1
      this.tableData.splice(insertIndex, 0, newRow)

      // 重新计算所有行的序号，确保连续
      this.updateLocalSequenceNumbers()

      // 检测序号变化并更新
      this.detectAndUpdateSequenceChanges()

      this.$message.success(`已复制"${record.caseName}"到下方`)
      console.log('在位置', insertIndex, '插入新行:', newRow)

      // 选中新粘贴的行
      this.selectedIndex = insertIndex
      this.selectedRow = newRow

      // 更新 copiedRow 用于其他可能的粘贴操作
      this.copiedRow = copiedData
    },
    /* 刷新描述信息 */
    async refreshDescriptions() {
      // await this.loadCaseDescriptions()
      this.$message.success('用例描述已刷新')
    },
    customRow(record, index) {
      return {
        class: {
          'drag-row': true,
          'selected-row': this.selectedIndex === index
        },
        on: {
          click: () => {
            this.selectRow(record, index)
          },
          keydown: event => {
            if (event.ctrlKey && event.keyCode === 67) {
              // Ctrl+C
              event.preventDefault()
              this.copyRow(event)
            } else if (event.ctrlKey && event.keyCode === 86) {
              // Ctrl+V
              event.preventDefault()
              this.pasteRow(event)
            }
          }
        },
        attrs: {
          tabindex: 0
        }
      }
    },
    /* 获取行类名 */
    getRowClassName(record, index) {
      return index === this.selectedIndex ? 'selected-row' : ''
    },

    /* 点击行时记录选中的行 */
    selectRow(record, index) {
      this.selectedIndex = index
      this.selectedRow = record
      console.log('选中行:', index, record)
    },

    /* 生成副本名称 */
    generateCopyName(originalName) {
      // 获取基础名称（移除所有副本后缀）
      const baseName = originalName.replace(/_副本(_\d+)?$/, '')

      // 获取所有以基础名称开头的用例名称
      const allNames = this.tableData.map(item => item.caseName)

      // 生成可能的副本名称模式
      let copyNumber = 1
      let newName = `${baseName}_副本`

      // 检查名称是否已存在，如果存在则递增编号
      while (allNames.includes(newName)) {
        copyNumber++
        newName = `${baseName}_副本_${copyNumber}`
      }

      console.log('生成副本名称:', { originalName, baseName, newName, copyNumber })
      return newName
    },

    /* 转义正则表达式特殊字符 */
    escapeRegExp(string) {
      return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
    },
    getTestList() {
      getAction(this.url.getTestById, { engineeringId: this.record.id, pageSize: -1 }).then(res => {
        if (res.success) {
          console.log(res, '获取测试用例数据')
          // 确保每条数据都有seq字段，如果没有则根据数组索引设置
          this.tableData = (res.result.records || []).map((item, index) => {
            return {
              ...item,
              seq: item.seq || index + 1
            }
          })

          // 备份原始数据用于比较变化
          this.backupTableData()
        } else {
          console.error('获取测试用例数据失败:', res)
        }
      })
    },
    // 添加：确保备份方法正确工作
    backupTableData() {
      this.originalTableData = JSON.parse(JSON.stringify(this.tableData))
      console.log(
        '数据备份完成，原始数据:',
        this.originalTableData.map(item => ({
          id: item.id,
          caseName: item.caseName,
          seq: item.seq
        }))
      )
    },
    /* 删除行 */
    async deleteRow(index, id) {
      try {
        const deletedRow = this.tableData[index]
        const deletedName = deletedRow.caseName

        // 先调用删除接口
        const res = await deleteAction(this.url.deleteTest, { id: id })

        if (res.success) {
          // 从数组中删除该行
          this.tableData.splice(index, 1)

          // 重新计算所有行的序号，确保连续
          this.updateLocalSequenceNumbers()

          // 检测序号变化并更新
          this.detectAndUpdateSequenceChanges()

          // 更新选中状态
          if (this.selectedIndex === index) {
            this.selectedIndex = Math.min(index, this.tableData.length - 1)
            if (this.selectedIndex >= 0) {
              this.selectedRow = this.tableData[this.selectedIndex]
            } else {
              this.selectedIndex = -1
              this.selectedRow = null
            }
          } else if (this.selectedIndex > index) {
            this.selectedIndex--
          }

          this.$message.success(`已删除用例: ${deletedName}`)
        } else {
          this.$message.error('删除失败: ' + (res.message || '未知错误'))
        }
      } catch (error) {
        console.error('删除失败:', error)
        this.$message.error('删除失败')
      }
    },
    /* 保存拖拽顺序 */
    saveOrder(evt) {
      console.log(
        '拖拽完成，新顺序:',
        this.tableData.map(item => ({ id: item.id, name: item.caseName, seq: item.seq }))
      )

      // 检测序号变化并更新
      this.detectAndUpdateSequenceChanges()
    },

    /* 检测序号变化并更新 */
    detectAndUpdateSequenceChanges() {
      // 保存拖拽前的原始数据（用于比较）
      const originalData = JSON.parse(JSON.stringify(this.originalTableData || []))

      // 当前数据
      const currentData = this.tableData

      // 找出序号发生变化的项
      const changedItems = this.findSequenceChanges(originalData, currentData)

      if (changedItems.length > 0) {
        console.log('序号变化的项:', changedItems)
        this.updateSequenceToBackend(changedItems)
      } else {
        console.log('序号没有变化，不调用接口')
      }
    },

    /* 找出序号发生变化的项 */
    findSequenceChanges(originalData, currentData) {
      const changedItems = []

      // 创建原始数据的映射，便于查找
      const originalMap = new Map()
      originalData.forEach(item => {
        originalMap.set(item.id, item)
      })

      // 检查当前数据中序号变化的项
      currentData.forEach((item, index) => {
        const originalItem = originalMap.get(item.id)
        const newSeq = index + 1

        if (originalItem) {
          // 如果序号发生了变化
          if (originalItem.seq !== newSeq) {
            changedItems.push({
              id: item.id,
              oldSeq: originalItem.seq,
              newSeq: newSeq
            })
          }
        } else {
          // 如果是新增的项（在复制操作中）
          changedItems.push({
            id: item.id,
            oldSeq: null,
            newSeq: newSeq
          })
        }
      })

      return changedItems
    },

    /* 调用后端API更新序号 - 仅更新变化的项 */
    /* 调用后端API更新序号 - 仅更新变化的项 */
    /* 调用后端API更新序号 - 循环单个更新 */
    async updateSequenceToBackend(changedItems) {
      if (changedItems.length === 0) {
        console.log('没有需要更新的序号')
        return
      }

      try {
        let successCount = 0
        let errorCount = 0

        // 循环更新每个变化的项
        for (const item of changedItems) {
          try {
            // 先获取当前记录的完整数据
            const currentRecord = this.tableData.find(record => record.id === item.id)
            if (!currentRecord) {
              console.warn(`未找到ID为 ${item.id} 的记录`)
              errorCount++
              continue
            }

            // 构建更新数据，只更新seq字段，其他字段保持原值
            const updateData = {
              ...currentRecord, // 包含所有原有字段
              seq: item.newSeq // 只更新seq字段
            }

            console.log(`更新记录 ${item.id}:`, {
              oldSeq: item.oldSeq,
              newSeq: item.newSeq
            })

            // 调用编辑接口
            const res = await httpAction('/testCaseEngineeringManagement/edit', updateData, 'post')

            if (res.success) {
              successCount++
            } else {
              errorCount++
              console.error(`更新记录 ${item.id} 失败:`, res.message)
            }
          } catch (error) {
            errorCount++
            console.error(`更新记录 ${item.id} 异常:`, error)
          }
        }

        if (errorCount === 0) {
          this.$message.success(`成功更新 ${successCount} 个用例的顺序`)

          // 更新本地数据的序号
          this.updateLocalSequenceNumbers()

          // 更新原始数据备份
          this.backupTableData()
        } else {
          this.$message.warning(`成功更新 ${successCount} 个，失败 ${errorCount} 个用例的顺序`)
          // 如果有部分失败，重新加载数据恢复原始顺序
          this.getTestList()
        }
      } catch (error) {
        console.error('更新序号失败:', error)
        this.$message.error('顺序更新失败')
        // 如果更新失败，重新加载数据恢复原始顺序
        this.getTestList()
      }
    },

    /* 更新本地数据的序号 */
    updateLocalSequenceNumbers() {
      this.tableData.forEach((item, index) => {
        item.seq = index + 1
      })
      console.log(
        '更新后的本地序号:',
        this.tableData.map(item => ({ id: item.id, seq: item.seq }))
      )
    },

    /* 点击复制按钮 */
    copyRowData(record) {
      this.copiedRow = { ...record }
      this.$message.success('已复制该行')
    },

    /* 保存拖拽顺序 */
    saveOrder(evt) {
      console.log(
        '拖拽完成，新顺序:',
        this.tableData.map(item => ({ id: item.id, name: item.caseName, seq: item.seq }))
      )

      // 重新计算所有行的序号，确保连续
      this.updateLocalSequenceNumbers()

      // 检测序号变化并更新
      this.detectAndUpdateSequenceChanges()
    },

    /* 打开配置 */
    openConfig(ymlPath, record, index) {
      console.log('打开配置弹窗:', {
        文件路径: ymlPath,
        记录: record,
        索引: index
      })

      // 更新文件路径和当前记录
      this.yamlFileUrl = ymlPath
      this.currentConfigRecord = record

      // 生成新的key来强制重新渲染ConfigForm
      this.configFormKey += 1

      // 显示配置弹窗
      this.showModal1()

      // 调试信息
      console.log('配置弹窗已打开，文件路径:', this.yamlFileUrl)
      console.log('当前配置记录:', this.currentConfigRecord)
    },
    saveOrder(evt) {
      console.log(
        '拖拽完成，新顺序:',
        this.tableData.map(item => ({ id: item.id, name: item.caseName, seq: item.seq }))
      )

      // 修复：拖拽完成后立即检测序号变化并更新
      this.$nextTick(() => {
        this.detectAndUpdateSequenceChanges()
      })
    },
    getTestUserCaseList() {
      getAction(this.url.testUserCaseList, { pageSize: -1, purpose: 2 }).then(res => {
        if (res.success) {
          this.tableData = res.result.records
        } else {
          console.error('getDictItems error: : ', res)
          this.dictOptions = []
        }
      })
    },
    onDrop(info) {
      console.log(info)
      const dropKey = info.node.eventKey
      const dragKey = info.dragNode.eventKey
      const dropPos = info.node.pos.split('-')
      const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1])
      const loop = (data, key, callback) => {
        data.forEach((item, index, arr) => {
          if (item.key === key) {
            return callback(item, index, arr)
          }
          if (item.children) {
            return loop(item.children, key, callback)
          }
        })
      }
      const data = [...this.gData]

      // Find dragObject
      let dragObj
      loop(data, dragKey, (item, index, arr) => {
        arr.splice(index, 1)
        dragObj = item
      })
      if (!info.dropToGap) {
        // Drop on the content
        loop(data, dropKey, item => {
          item.children = item.children || []
          // where to insert 示例添加到尾部，可以是随意位置
          item.children.push(dragObj)
        })
      } else if (
        (info.node.children || []).length > 0 && // Has children
        info.node.expanded && // Is expanded
        dropPosition === 1 // On the bottom gap
      ) {
        loop(data, dropKey, item => {
          item.children = item.children || []
          // where to insert 示例添加到尾部，可以是随意位置
          item.children.unshift(dragObj)
        })
      } else {
        let ar
        let i
        loop(data, dropKey, (item, index, arr) => {
          ar = arr
          i = index
        })
        if (dropPosition === -1) {
          ar.splice(i, 0, dragObj)
        } else {
          ar.splice(i + 1, 0, dragObj)
        }
      }
      this.gData = data
    },
    /* 显示配置弹窗 */
    showModal1() {
      this.visible1 = true
      console.log('配置弹窗显示状态:', this.visible1)
    },
    handleOk(e) {
      this.confirmLoading = true
      console.log(this.tableData, 'tabel')

      setTimeout(() => {
        this.visible = false
        this.confirmLoading = false
      }, 2000)
    },
    handleCancel(e) {
      console.log('Clicked cancel button')
      this.visible = false
    },
    /* 配置弹窗确定 */
    handleOk1(e) {
      console.log('配置弹窗确定')
      this.confirmLoading1 = true

      // 这里可以添加保存配置的逻辑
      setTimeout(() => {
        this.visible1 = false
        this.confirmLoading1 = false
        this.$message.success('配置保存成功')
      }, 1000)
    },
    handleCancel1(e) {
      console.log('配置弹窗取消')
      this.visible1 = false
      this.yamlFileUrl = ''
      this.currentConfigRecord = null
    },
    /* 配置表单提交成功 */
    handleSubmitSuccess(values) {
      console.log('配置提交成功:', values)
      // 关闭配置弹窗
      this.visible1 = false
      this.$message.success('配置保存成功')

      // 这里可以处理提交成功后的逻辑
      if (this.currentConfigRecord) {
        console.log('更新记录配置状态:', this.currentConfigRecord.caseName)
        // 可以在这里更新记录的配置状态
      }
    },

    initDictConfig() {},
    getSuperFieldList() {
      let fieldList = []
      fieldList.push({ type: 'string', value: 'tester', text: '测试人员', dictCode: '' })
      fieldList.push({ type: 'string', value: 'testDescription', text: '测试描述', dictCode: '' })
      fieldList.push({ type: 'string', value: 'testName', text: '测试名称', dictCode: '' })
      fieldList.push({ type: 'string', value: 'userCaseIds', text: '关联用例id', dictCode: '' })
      fieldList.push({ type: 'string', value: 'equipName', text: '目标设备名称', dictCode: '' })
      fieldList.push({ type: 'string', value: 'equipCode', text: '目标设备编号', dictCode: '' })
      this.superFieldList = fieldList
    }
  }
}
</script>
<style scoped>
@import '~@assets/less/common.less';
</style>
<style>
/* 新增描述单元格样式 */
.description-cell {
  max-width: 300px;
  min-width: 250px;
}

.description-content {
  max-height: 60px;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  line-height: 1.4;
  font-size: 12px;
  color: #666;
}

/* 操作按钮区域添加刷新按钮样式 */
.refresh-btn {
  margin-left: 8px;
}

/* 调整表格列宽 */
.config-table {
  width: 100%;
  overflow-x: auto;
}

.config-table table {
  min-width: 800px; /* 确保表格有足够宽度 */
}

/* 其他样式保持不变 */
.ConfigList .ant-table-thead > tr > th {
  background-color: #fafafa;
  font-weight: 600;
  padding: 12px 8px;
}

.ConfigList .ant-table-tbody > tr > td {
  padding: 8px;
  border-bottom: 1px solid #e8e8e8;
}

.ConfigList .drag-row {
  cursor: pointer;
  transition: all 0.3s;
}

.ConfigList .drag-row:hover {
  background-color: #f5f5f5;
}

.ConfigList .selected-row {
  background-color: #e6f7ff !important;
  border: 1px solid #1890ff;
}

.ConfigList .drag-handle {
  cursor: move;
  color: #999;
}

.ConfigList .drag-handle:hover {
  color: #1890ff;
}
/* 全局样式，确保能应用到模态框内的表格 */
/* ConfigList 表格样式 */
.ConfigList .ant-table-thead > tr > th {
  background-color: #fafafa;
  font-weight: 600;
  padding: 12px 8px;
}

.ConfigList .ant-table-tbody > tr > td {
  padding: 8px;
  border-bottom: 1px solid #e8e8e8;
}

.ConfigList .drag-row {
  cursor: pointer;
  transition: all 0.3s;
}

.ConfigList .drag-row:hover {
  background-color: #f5f5f5;
}

.ConfigList .selected-row {
  background-color: #e6f7ff !important;
  border: 1px solid #1890ff;
}

.ConfigList .drag-handle {
  cursor: move;
  color: #999;
}

.ConfigList .drag-handle:hover {
  color: #1890ff;
}

/* 手动表格样式 */
.config-table {
  width: 100%;
}

.config-table table {
  border: 1px solid #e8e8e8;
  border-collapse: collapse;
  width: 100%;
}

.config-table th {
  background-color: #fafafa;
  padding: 12px 8px;
  border-bottom: 1px solid #e8e8e8;
  font-weight: 600;
  text-align: center;
}

.config-table td {
  padding: 8px;
  border-bottom: 1px solid #e8e8e8;
  text-align: center;
}

/* 拖拽样式 */
.sortable-ghost {
  opacity: 0.5;
  background-color: #f0f0f0;
}

.sortable-chosen {
  background-color: #e6f7ff;
}
.description-text {
  white-space: pre-line; /* 保留换行符 */
  line-height: 1.5;
  text-align: left;
  max-height: 60px;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
}
/* Tooltip内容样式 - 支持换行显示 */
.tooltip-content {
  white-space: pre-line; /* 保留换行符 */
  line-height: 1.6;
  max-width: 400px;
  max-height: 300px;
  overflow: auto;
  font-size: 13px;
  color: #fff;
  text-align: left;
}
</style>
